#define _CRT_SECURE_NO_WARNINGS
#include "RLPlanningEngine.h"
#include "RLPlatformData.h"
#include "algohub_common_type.h"
#include "reader/NCoreReader.h"
#include "helper/NCorePathHelper.h"
#include <iostream>
#include <vector>
#include <string>
#include <cassert>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <filesystem>

// Function to create a mock DimsArray object for testing
darr::DimsArray<float> create_mock_depth_data(double min_lon, double max_lon, double min_lat, double max_lat, int year)
{
    std::map<algobase::EvaluateEnvirDataType, std::map<std::string, darr::DimsArray<float>>> result;
    std::map<std::string, darr::DimsArray<float>> dp_result;

    ncore::reader::Area area(min_lon, max_lon, min_lat, max_lat, 0.0, 20000);
    ncore::helper::PathHelper pathHelper;

    algobase::Date loop_date(year, 0, 0);

    std::string file_name = pathHelper.getDBDirPath() + "/dp/GEBCO_" + std::to_string(year) + ".nc";
    if (file_name.empty()) {
        return {};
    }

    ncore::reader::NCoreReaderResult<float> loop_read_result;
    ncore::reader::NCoreReader reader(file_name);
    bool read_exec_result = reader.readArea<float>(area, loop_read_result);
    if (!read_exec_result) {
        return {};
    }

    return std::move(loop_read_result["elevation"]);
}

int main()
{
    // --- Create a timestamped directory for output ---
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);
    std::stringstream ss;
    ss << "test_run_" << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S");
    std::string output_dir = ss.str();
    std::filesystem::create_directory(output_dir);
#ifdef RL_DEBUG
    std::cout << "Outputting results to directory: " << output_dir << std::endl;
#endif


    // 1. --- Set up run configuration ---
    // Platform parameters (can be extended later)
    algo::RLPlatformData platformData;

    // Environment area parameters
    double min_lon = 140.0, max_lon = 141.0;
    double min_lat = 30.0, max_lat = 31.0;
    int year = 2023;

    // Start and end points for the path planning
    algobase::Coord startPos = { 140.1, 30.1 };
    algobase::Coord endPos = { 140.9, 30.9 };

    // 2. --- Load Environment Data ---
    darr::DimsArray<float> depth_data = create_mock_depth_data(min_lon, max_lon, min_lat, max_lat, year);
    if (depth_data.isEmpty()) {
        std::cerr << "Failed to load depth data. Exiting." << std::endl;
        return 1;
    }
    
#ifdef RL_DEBUG
    std::cout << "Starting RLPlanningEngine execution..." << std::endl;
#endif

    // 3. Instantiate and execute RLPlanningEngine directly
    // 3. --- Run Reinforcement Learning ---
    algobase::RLConfig config; // Create a config object
    config.num_episodes = 2000; // Increase training episodes
    config.alpha = 0.1; // Lower learning rate for stability
    config.gamma = 0.95; // Higher discount factor for long-term planning

#ifdef RL_DEBUG
    // --- Print RL Configuration ---
    std::cout << "\n--- RL Configuration ---" << std::endl;
    std::cout << "Episodes: " << config.num_episodes << std::endl;
    std::cout << "Max Steps per Episode: " << config.max_steps_per_episode << std::endl;
    std::cout << "Learning Rate (Alpha): " << config.alpha << std::endl;
    std::cout << "Discount Factor (Gamma): " << config.gamma << std::endl;
    std::cout << "Epsilon Start: " << config.epsilon_start << std::endl;
    std::cout << "Epsilon Decay: " << config.epsilon_decay << std::endl;
    std::cout << "Epsilon Min: " << config.epsilon_min << std::endl;
    std::cout << "------------------------\n" << std::endl;
#endif

    algo::RLPlanningEngine planningEngine(platformData, depth_data, config);
    // Pass the output directory to the findPath method
    algobase::Path path = planningEngine.findPath(startPos, endPos, output_dir);

#ifdef RL_DEBUG
    std::cout << "RLPlanningEngine execution finished." << std::endl;
#endif

    // 4. Assertions and Verification
    assert(!path.empty());
#ifdef RL_DEBUG
    std::cout << "Path generated with " << path.size() << " points." << std::endl;

    // Print the full path to the console
    std::cout << "--- Final Path ---" << std::endl;
    std::cout << std::fixed << std::setprecision(6);
    for (size_t i = 0; i < path.size(); ++i) {
        const auto& p = path[i];
        std::cout << "Point " << i << ": ("
                  << p.mCoordZ[0] << ", "
                  << p.mCoordZ[1] << ", "
                  << p.mCoordZ[2] << ")" << std::endl;
    }
    std::cout << "------------------" << std::endl;

    std::cout << "Test passed!" << std::endl;
#endif

    return 0;
}